﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using ValidationFramework.Reflection;
using Rhino.Mocks;
using ValidationFramework.Tests.TestHelpers;
namespace ValidationFramework.Tests
{
	[TestFixture]
	public class TypePolicyRepositoryTest
	{
        public class Person
        {
            public string Name { get; set; }
        }
		public class Student : Person
		{
            public double GPA { get; set; }
		}
        public class Pet
        {
            public string Name { get; set; }
        }

		[Test]
		public void GetPropertyPolicies_Should_Return_All_Policies_For_Objects_Properties()
		{
            var reflectionCache = new ReflectionCache();
            var mockAppDesciber = MockRepository.GenerateStub<IApplicationDesciber>();
            mockAppDesciber.Expect(x => x.GetAllChildTypes(typeof(Person)))
                .Return(new List<Type>() 
                    { 
                        typeof(Student) 
                    });

            var repository = new TypePolicyRepository(new ValidationPolicyFactory(reflectionCache), mockAppDesciber);
			var typeKey = new TypeKey(typeof(Person).TypeHandle);
			var mockRule = MockRepository.GenerateStub<Rule>(new AlwaysFailValidator());

            repository.AddPropertyRule(new PropertyKey(typeKey, "GPA"), mockRule, RuleScope.Parent);
            repository.AddPropertyRule(new PropertyKey(typeKey, "GPA"), mockRule, RuleScope.Member);


            var policies = repository.GetPropertyPoliciesForType(typeKey);
			Assert.AreEqual(1, policies.Count);
            Assert.AreEqual("GPA", policies[0].MemberName);	
		}

        [Test]
        public void Should_Multicast_Property_Rules_To_All_Child_Types()
        {
            // Arrange
            var reflectionCache = new ReflectionCache();
            var mockAppDesciber = MockRepository.GenerateStub<IApplicationDesciber>();
            mockAppDesciber.Expect(x => x.GetAllChildTypes(typeof(Person)))
                .Return(new List<Type>() 
                    { 
                        typeof(Student) 
                    });
            var repository = new TypePolicyRepository(new ValidationPolicyFactory(reflectionCache), mockAppDesciber);
            repository.MulticastingOfRulesEnabled = true;

            var typeKey = new TypeKey(typeof(Person));
            var mockRule = MockRepository.GenerateStub<Rule>(new AlwaysFailValidator());

            var personProperty = new PropertyKey(new TypeKey(typeof(Person)), "Name");
            var studentProperty = new PropertyKey(new TypeKey(typeof(Student)), "Name");

            // Assume
            Assert.AreEqual(0, repository.GetPropertyPolicy(personProperty).RuleCount);
            Assert.AreEqual(0, repository.GetPropertyPolicy(studentProperty).RuleCount);

            // Act
            repository.AddPropertyRule(personProperty, mockRule, RuleScope.Parent);

            // Assert
            Assert.AreEqual(1, repository.GetPropertyPolicy(personProperty).RuleCount);
            Assert.AreEqual(1, repository.GetPropertyPolicy(studentProperty).RuleCount);
        }

        [Test]
        public void Should_Not_Add_Rules_To_Non_Child_Types()
        {
            // Arrange
            var reflectionCache = new ReflectionCache();
            var mockAppDesciber = MockRepository.GenerateStub<IApplicationDesciber>();
            mockAppDesciber.Expect(x => x.GetAllChildTypes(typeof(Person)))
                .Return(new List<Type>());
            var repository = new TypePolicyRepository(new ValidationPolicyFactory(reflectionCache), mockAppDesciber);
            repository.MulticastingOfRulesEnabled = true;

            var mockRule = MockRepository.GenerateStub<Rule>(new AlwaysFailValidator());

            const string STR_PropertyName = "Name";
            var personProperty = new PropertyKey(new TypeKey(typeof(Person)), STR_PropertyName);
            var petProperty = new PropertyKey(new TypeKey(typeof(Pet)), STR_PropertyName);

            // Assume
            Assert.AreEqual(0, repository.GetPropertyPolicy(personProperty).RuleCount);
            Assert.AreEqual(0, repository.GetPropertyPolicy(petProperty).RuleCount);

            // Act
            repository.AddPropertyRule(personProperty, mockRule, RuleScope.Parent);

            // Assert
            Assert.AreEqual(1, repository.GetPropertyPolicy(personProperty).RuleCount);
            Assert.AreEqual(0, repository.GetPropertyPolicy(petProperty).RuleCount);
        }
	}
}
